Por medio de la ciencia de datos nos ayudamos a transformar y a entender los datos para tomar decisiones. Antes de comenzar a realizar análisis de datos, debemos realizar una exploración de ellos, entender los datos, para generar hipótesis, probarlas y luego repetirlas o ponerlas en marcha.
Para realizar mejores análisis se recomienda el ciclo de vida del proceso de ciencia de datos en equipo (TDSP), el cual es un proceso para estructural los proyectos de ciencia de datos.
Este ciclo de vida está diseñado para proyecto de ciencia de datos va desde la adquisición de los datos y entendimiento del problema, hasta la puesta en producción. Estas aplicaciones implementan modelos de aprendizaje o inteligencia artificial de máquina para realizar un análisis predictivo/clasificación. Los proyectos de ciencia de datos exploratorios y los proyectos de análisis improvisados también se pueden beneficiar del uso de este proceso. Pero para esos proyectos, algunos de los pasos descritos a continuación pueden no ser necesarios.
El ciclo de vida de TDSP se compone por cinco fases principales de forma iterativa (Figura 1):
Entender el negocio
Adquisición y comprensión de los datos
Modelado
Implementación
Aceptación del cliente
La exploración de datos es el arte de entender los datos, generar hipótesis e investigar las características de los datos (transformar registros en información). El objetivo de la exploración de datos es extraer información y tomar mejores decisiones para el modelo que se va a desarrollar.
La visualización de datos, es una de las formas de exploración más utilizadas. Las visualizaciones por si solas no suelen ser suficientes, por lo que se vuelve necesario procesar y transformar los datos, por medio de friltrados, creación de nuevas variables y cálculos (ingeniería de características), por ejemplo.
Finalmente, la combinación de la visualización y la transformación de los datos con su curiosidad y análisis, nos llevará a la extracción de información resolución de preguntas a cerca de los datos.
Comencemos a utilizar R_Studio y algunas de las paqueterías
que nos ayudarán a entender los datos. Para la visualización de datos
utilizaremos la paquetería ggplot2, aclarando que no es la
única herramienta para hacerlo. Aquí puedes descargar algunos trucos de
ggplot (ggplot2
cheatsheets).
ggplot2
Una de las paqueterías principales que vamos a utilizar es
tidyverse y la cual es indispensable para el funcionamiento
de ggplot2. Ahora la pregunta es ¿qué es
tidyverse,? a continuación hablaremos sobre esta
paquetería.
tidyverse?El tidyverse es
un conjunto de paquetes en R diseñados para ciencia de datos.
Todos los paquetes comparten una filosofía de diseño, una gramática y
estructuras de datos subyacentes.
Todos estos paquetes nos ayudan a importar, ordenar, transformar y así entender los datos, para finalmente poder obtener y comunicar sus resultados de forma más fácil.
Figura 3. tidyverse
Se pueden instalar todos los paquetes desde tidyverse
simplemente escribiendo en tu consola de R
install.packages("tidyverse").
# Sólo se necesita instalar la primera vez este paquete en tu computadora
install.packages("tidyverse")Para que funcione este paquete, siempre en nuestro proyecto debemos de cargar su librería corriendo el siguiente código:
library(tidyverse)Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
── Attaching packages ──────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.5 ✓ purrr 0.3.4
✓ tibble 3.1.2 ✓ dplyr 1.0.7
✓ tidyr 1.1.3 ✓ stringr 1.4.0
✓ readr 1.4.0 ✓ forcats 0.5.1
── Conflicts ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
En el código, si se necesita ser explicito de una función o dataset
de un paquete en particular, podemos usar la función
form_package::function(). Por ejemplo,
ggplot2::ggplot() dice que, explícitamente, se quiere usar
la función ggplot() del paquete ggplot2.
Hay muchos paquetes que usaremos que cumplen con la estructura de los
datos y las práticas de tidyverse que deben instalarse de
forma independiente usando el comando
install.packages("package") y luego cargar su librería.
Algunos de los que usaremos será lubridate y tsibble,
que son paquetes especiales para fechas.
El comando %>% que se conoce como pipe o en
español tubería, es un comando que sólo funciona con la
librería de tidyverse. Se utiliza para enfatizar una
secuencia de acciones comenzando con un conjunto de datos. Debe de estar
antecedido de una línea y es más fácil de entender si se hacen acciones
por líneas. Se puede leer este comando en el código como si fuera un
luego, qué es lo que sigue, en la ejecución y realizar en una
sola línea varias acciones.
Para los ejemplo usaremos una base de datos de créditos
de Alemania, los cuales se extrageron de kaggle.
Un resumen de la descripción de las categorías se presenta a continuación: - Edad (numérico) - Sexo (texto: masculino, femenino) - Trabajo (numérico: 0 - no cualificado y no residente, 1 - no cualificado y residente, 2 - cualificado, 3 - muy cualificado) - Vivienda (texto: propia, de alquiler o gratuita) - Cuentas de ahorro (texto: poco, moderado, bastante, mucho) - Cuenta corriente (numérico, en DM - marco alemán) - Importe del crédito (numérico, en DM) - Duración (numérico, en meses) - Finalidad (texto: coche, muebles/equipamiento, radio/TV, electrodomésticos, reparaciones, educación, negocios, vacaciones/otros)
Traducción realizada con la versión gratuita del traductor www.DeepL.com/Translator
data <- read.csv("https://datahub.io/machine-learning/credit-g/r/credit-g.csv")
head(data)Podemos interpretar el pipe con la palabra luego. Por
ejemplo, tomando los datos de crédito anterior y queremos un filtro de
la varibale housing por own, usando R base y
luego usando tidiverse con el comando
%>%:
# R base
head(filter(data,housing == 'own'))# Tidiverse con el pipe %>%
data %>% filter(housing == 'own') %>% head()En la última línea obtenemos el mismo resultado que si lo hacemos con
R base, solo que podemos ir interpretando más fácilmente el código. Este
se puede leer como toma data y luego aplica un filtro a la
variable Sex = 'male' y luego muestra los primeros 6
registros (encabezado).
Un ejemplo de utilización del pipe se puede ser:
data %>% group_by(class,personal_status) %>%
summarise(n= n(), avg_existing_credits = mean(existing_credits)) %>%
arrange(personal_status,-n)`summarise()` has grouped output by 'class'. You can override using the `.groups` argument.
ggplot2Para ejemplificar la visualización en R analizaremos el
conjunto de datos (variables en las columnas y observaciones en las
filas) que contiene datos recopilados de la Agencia de Protección
Ambiental de Estados Unidos para 38 modelos de autos. Este data
frame se encuentra en R con la función mpg, el nombre de
este data frame viene de la abreviación de (miles per gallon o en
español, millas por galón (mpg)). Para tener mayor información sobre
mpg, pueden abrir ayuda y buscar esta función o en su
consola correr el comando ?mpg.
Para mirar cuáles son las variables (nombre las columnas) lo podemos
hacer con la función colnames() y para sacar un resumen de
nuestros datos utilizamos la función summary().
colnames(mpg) [1] "manufacturer" "model" "displ" "year" "cyl" "trans" "drv" "cty" "hwy"
[10] "fl" "class"
summary(mpg) manufacturer model displ year cyl trans drv cty
Length:234 Length:234 Min. :1.600 Min. :1999 Min. :4.000 Length:234 Length:234 Min. : 9.00
Class :character Class :character 1st Qu.:2.400 1st Qu.:1999 1st Qu.:4.000 Class :character Class :character 1st Qu.:14.00
Mode :character Mode :character Median :3.300 Median :2004 Median :6.000 Mode :character Mode :character Median :17.00
Mean :3.472 Mean :2004 Mean :5.889 Mean :16.86
3rd Qu.:4.600 3rd Qu.:2008 3rd Qu.:8.000 3rd Qu.:19.00
Max. :7.000 Max. :2008 Max. :8.000 Max. :35.00
hwy fl class
Min. :12.00 Length:234 Length:234
1st Qu.:18.00 Class :character Class :character
Median :24.00 Mode :character Mode :character
Mean :23.44
3rd Qu.:27.00
Max. :44.00
Queremos responder la pregunta: ¿Los autos con motor más grandes usan más combustible que los autos con motor más pequeño.? Probablemente ya tenga una respuesta, pero, intentemos que su respuesta sea precisa. ¿Cómo se ve la relación entre el tamaño del motor y la eficiencia del combustible? ¿Es positivo? ¿es negativo? ¿es lineal? ¿es no lineal.?
Hay dos variables en nuestro data frame de mpg
que nos podrían ayudar a responder:
displ indica el tamaño del motor en litros
hwy indica la eficiencia de combustible del auto en
carretera en millas por galón (mpg)
Para realizar el gráfico vamos a poner la variable del tamaño del
motor (displ) en el eje x y la eficiencia
(hmy) en el eje y y utilizaremos la paquetería
ggplot2.
# Cargar la paquetería de ggplot2
library("ggplot2")
# Grafico
mpg %>% ggplot(aes(x = displ, y = hwy)) En el comando anterior primero estamos tomando los datos
mpg, luego %>% tomamos la función
ggplot() y le estamos especificando los ejes con la función
aes(), pero aún no le hemos especificado qué tipo de
gráfico será, es por ello que no nos muestra ninguna visualización.
Si por ejemplo queremos que cada dato lo muestre como un punto, vamos
a adicionar al ggplot con un más (+) la
función geom_point(). Para ver otros tipos de gráficos nos
podemos apoyar de la hoja de trucos de ggplot2 presentada
en la sesión de introducción.
# Grafico
mpg %>% ggplot(aes(x = displ, y = hwy)) +
geom_point()Por lo tanto, a continuación mostramos de forma generar los pasos
para describir cómo funciona un gráfico ggplot2:
Comencemos con un objeto ggplot (), donde
especifique los datos que se utilizarán,
proporcionar el mapeo estético (con
aes ()),
agreguemos capas:
Si desea un diagrama de dispersión, use
geom_point (), histograma geom_hist (). Otros
gráficos comunes son geom_line (),
geom_bar (), geom_boxplot ().
definir escalas de color, como scale_color_brewer ()
o scale_color_distiller (),
especificaciones de facetas facet_wrap () o
facet_grid ()
sistemas de coordenadas, como coord_cartesian (),
coord_flip ()
Cada elemento está separado con un signo más (** + **):
ggplot(mpg, aes(displ, hwy, colour = class)) +
geom_point() +
facet_wrap(~manufacturer)Debemos tener en cuenta que ggplot2 trabaja por capas,
si deseamos que todo el gráfico tenga algo debemos de hacerlo desde la
función primaria ggplot(), de lo contrario lo podemos hacer
en las capas subyacentes. Para entender esta diferencia veamos las dos
siguientes visualizaciones:
# El color aplica a todo el gráfico porque está en la función principal ggplot()
ggplot(mpg, aes(displ, hwy,color = class)) +
geom_point() +
geom_smooth()
# El color sólo aplica a los puntos y no toma en cuenta geom_smooth()
ggplot(mpg, aes(displ, hwy)) +
geom_point(aes(color = class)) +
geom_smooth()La exploración de los datos nos puede proporcionar información dinámica, encontrar patrones y entender la historia de los datos. Es importante, antes de comenzar a entrar en el modelo, realizar un Análisis Exploratorio de los datos o en inglés Exploratory Data Analysis (EDA).
Para realizar este análisis, debemos hacer hipótesis respecto a los datos, transformar e inspeccionar de forma visual las propiedades estadísticas de los datos.
Cuál es el comportamiento en el tiempo de la variable (si aplica),
cuál es la variación de la variable,
identificación de valores atípicos,
distribuciones y variables estadísticas.
Algunos ejemplos:
Para comparar variables categóricas podemos usar diagramas de barras
(geom_var()):
diamonds %>% ggplot() +
geom_bar(mapping = aes(x = cut)) +
ggtitle("Count of Diamonds by cut quality")Otra opción para entender las variables categóricas es hacer diagramas de cajas/bigotes o boxplots:
mpg %>% ggplot() +
geom_boxplot(mapping = aes(x = reorder(class, hwy, FUN = median), y = hwy))+ labs(x = "class", y = "hwy mpg")Para variables continuas, podemos utilizar un histograma de
frecuencias, especificando el tamaño de la clase con
binwidth:
diamonds %>% ggplot() +
geom_histogram(mapping = aes(x = carat), binwidth = 0.5) +
ggtitle("Histogram of carats")Si queremos visualizar histogramas de múltiples variables en un sólo
gráfico, se puede usar la función geom_freqpoly() o usar
facetas dentro de ggplot2``:
ggplot(data = diamonds %>% filter(carat < 3), mapping = aes(x = carat, colour = cut)) +
geom_freqpoly(binwidth = 0.1)ggplot(data = diamonds %>% filter(carat < 3), mapping = aes(x = carat, fill = cut)) +
geom_histogram(binwidth = 0.1) +
facet_wrap(~ cut) +
theme(legend.position = "none")library(gridExtra)
Attaching package: ‘gridExtra’
The following object is masked from ‘package:dplyr’:
combine
library(grid)
g <- ggplot(data = diamonds %>% filter(carat < 3), mapping = aes(x = carat))
g0 <- g + geom_histogram(binwidth = 0.5) +
ggtitle("Binwidth = 0.5")
g1 <- g + geom_histogram(binwidth = 0.1) +
ggtitle("Binwidth = 0.1")
g2 <- g + geom_histogram(binwidth = 0.01) +
ggtitle("Binwidth = 0.01")
grid.arrange(g0,g1,g2,
top = "Histograms varying the binwidth",
bottom = textGrob(
"Different patterns can arise when selecting different binwidths",
gp = gpar(fontface = 3, fontsize = 9),
hjust = 1,
x = 1))Los anteriores son sólo algunos ejemplos, pero podría realizar muchísimas más visualizaciones como scatterplots, por ejemplo.
También podemos realizar reportes completos con
DataExplorer::create_report(). Para el siguiente ejemplo
debemos instalar los paquetes DataExplorer y
nycflights13 para los datos
(install.packages("nycflights13")).
library(nycflights13)
library(DataExplorer)Registered S3 method overwritten by 'data.table':
method from
print.data.table
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
En el paquete library(DataExplorer) hay 5 data
frames:
airlines
airports
flights
planes
weather
Podemos visualizar su estructura de la siguiente forma:
data <- list(airlines, airports, flights, planes, weather)
plot_str(data)Para tener un sólo dataset más robusto podemos fusionar las tablas
por medio de la función merge()
final_data <- flights %>% merge(airlines, by= "carrier", all.x = TRUE) %>%
merge(planes, by = "tailnum", all.x = TRUE, suffixes = c("_flights", "_planes")) %>%
merge(airports, by.x = "origin", by.y = "faa", all.x = TRUE, suffixes = c("_carrier", "_origin")) %>%
merge(airports, by.x = "dest", by.y = "faa", all.x = TRUE, suffixes = c("_origin", "_dest"))DataExplorerPara conocer el conjunto de datos podemos realizar un
summary() como lo hicimos en la sesión anterior o podemos
utilizar la función introduce().
introduce(final_data)
# De forma gráfica
plot_intro(final_data)Debemos de notar algo en este conjunto de datos:
Sólo el 0.27% de las filas están completas,
tenemos 5.7% de observaciones faltantes, es decir, dado que solo tenemos 0.27% de las filas completas, solo hay 5.7% de observaciones faltantes del total.
Estos valores faltantes nos podrán general problemas para analizar los datos, veamos un poco los perfiles que faltan.
Siempre, en todos los problemas reales, vamos a tener datos
desordenados y con problemas. Para visualizar el perfil de los datos
faltantes podemos utilizar la función plot_missing().
plot_missing(final_data)Si le gusta más tener la información en forma de tabla puede obtener
su perfil por medio de la función
profile_missing(final_data).
En la visualización anterior, podemos ver que la variable
speed es la que en su mayoría le falta información, al
parecer encontramos el culpable de que sólo el 0.27% de nuestras filas
estén completas y probablemente esta variable no sea de mucha
información. Por tanto la podemos eliminar de nuestro dataframe.
final_data <- drop_columns(final_data, "speed")La visualización de las distribuciones de frecuencia para todas las
características discretas se puede realizar con la función
plot_bar().
plot_bar(final_data)5 columns ignored with more than 50 categories.
dest: 105 categories
tailnum: 4044 categories
time_hour: 6936 categories
model: 128 categories
name: 102 categories
Tras una inspección detallada de la variable
manuracturer, no es fácil identificar las siguientes
características duplicadas:
AIRBUS and AIRBUS INDUSTRIE
CANADAIR and CANADAIR LTD
MCDONNELL DOUGLAS, MCDONNELL DOUGLAS AIRCRAFT CO and MCDONNELL DOUGLAS CORPORATION
Por tanto, debemos proceder a limpiar esta variable
final_data[which(final_data$manufacturer == "AIRBUS INDUSTRIE"),]$manufacturer <- "AIRBUS"
final_data[which(final_data$manufacturer == "CANADAIR LTD"),]$manufacturer <- "CANADAIR"
final_data[which(final_data$manufacturer %in% c("MCDONNELL DOUGLAS AIRCRAFT CO", "MCDONNELL DOUGLAS CORPORATION")),]$manufacturer <- "MCDONNELL DOUGLAS"
plot_bar(final_data$manufacturer)Adicionalmente, las variables dst_origin,
tzone_origin, year_flights y
tz_origin contienen un solo valor, por lo que deberíamos
proceder a eliminarla, ya que no nos proporciona información:
final_data <- drop_columns(final_data, c("dst_origin", "tzone_origin", "year_flights", "tz_origin"))Con frecuencia, es muy beneficioso observar la distribución de
frecuencia bivariada. Por ejemplo, para ver características discretas
por arr_delay:
plot_bar(final_data, with = "arr_delay")5 columns ignored with more than 50 categories.
dest: 105 categories
tailnum: 4044 categories
time_hour: 6936 categories
model: 128 categories
name: 102 categories
Nótese que la distribución resultante se ve bastante diferente de la distribución de frecuencias regular.
Puede optar por dividir por colores todas las frecuencias por una
variable discreta, como por ejemplo origin:
plot_bar(final_data, by = "origin")5 columns ignored with more than 50 categories.
dest: 105 categories
tailnum: 4044 categories
time_hour: 6936 categories
model: 128 categories
name: 102 categories
Para visualizar distribuciones de todas las variables continuas
podemos utilizar la función plot_histogram():
plot_histogram(final_data)También podemos observar que hay variables de fechas y horas que
deben tratarse un poco más, por ejemplo, concentrando año, mes, día para
formar una variable de fecha y/o agregar hora y minuto para
formar la variable fecha_hora.
Otra parte que podemos limpiar, es por ejemplo la variable
flight, ya que esa deberíamos tenerla como un factor, por
ser un número de vuelo y numéricamente no tiene ningún significado:
final_data <- update_columns(final_data, "flight", as.factor)También podemos remover las variables year_flights y
tz_origin ya que sólo contienen un valor:
final_data <- drop_columns(final_data, c("year_flights", "tz_origin"))Warning: Column 'year_flights' does not exist to removeWarning: Column 'tz_origin' does not exist to remove
La gráfica Quantile-Quantile es una forma de visualizar la desviasión de una distribución de probabilidad específica.
Después de analizar estos gráficos, a menudo es beneficioso aplicar
una transformación matemática (como logaritmo) para modelos como la
regresión lineal. Para hacerlo, podemos usar la función
plot_qq. De forma predeterminada, se compara con la
distribución normal.
Nota: La función llevará mucho tiempo con muchas observaciones, por
lo que puede optar por especificar un sampled_rows
apropiado:
qq_data <- final_data[, c("arr_delay", "air_time", "distance", "seats")]
plot_qq(qq_data, sampled_rows = 1000L)En el gráfico, air_time, distance y
asientos parecen sesgados en ambas colas. Apliquemos una transformación
logarítmica simple y grafiquemos de nuevo.
log_qq_data <- update_columns(qq_data, 2:4, function(x) log(x + 1))
plot_qq(log_qq_data[, 2:4], sampled_rows = 1000L)Con esto obtener una mejor distribución. Si es necesario, también puede ver el gráfico QQ mediante otra función:
qq_data <- final_data[, c("name_origin", "arr_delay", "air_time", "distance", "seats")]
plot_qq(qq_data, by = "name_origin", sampled_rows = 1000L)Para visualizar el mapa de calor de la correlación de todas las variables que no tengan datos faltantes lo podemos realizar de la siguiente forma:
plot_correlation(na.omit(final_data), maxcat = 5L)11 features with more than 5 categories ignored!
dest: 100 categories
tailnum: 3246 categories
carrier: 16 categories
flight: 3773 categories
time_hour: 6642 categories
name_carrier: 16 categories
manufacturer: 24 categories
model: 121 categories
engine: 6 categories
name: 100 categories
tzone_dest: 7 categories
También puede graficar variables sólo discretas/continuas de la siguiente forma:
plot_correlation(na.omit(final_data), type = "c")plot_correlation(na.omit(final_data), type = "d")7 features with more than 20 categories ignored!
dest: 100 categories
tailnum: 3246 categories
flight: 3773 categories
time_hour: 6642 categories
manufacturer: 24 categories
model: 121 categories
name: 100 categories
El análisis de componentes principales (PCA, por sus siglas en inglés,) consiste en expresar un conjunto de variables en un conjunto de combinaciones lineales de factores no correlacionados entre sí, estos factores dando cuenta una fracción cada vez más débil de la variabilidad de los datos.
Este análisis lo podemos realizar directamente con la función
plot_prcomp (na.omit (final_data)), pero PCA funcionará
mejor si limpiamos los datos primero:
pca_df <- na.omit(final_data[, c("origin", "dep_delay", "arr_delay", "air_time", "year_planes", "seats")])
plot_prcomp(pca_df, variance_cap = 0.9, nrow = 2L, ncol = 2L)Suponga que le gustaría construir un modelo para predecir los retrasos en las llegadas, puede visualizar la distribución de todas las características continuas en función de los retrasos en las llegadas con un diagrama de caja/bigotes (boxplot):
## Reduce data size for demo purpose
arr_delay_df <- final_data[, c("arr_delay", "month", "day", "hour", "minute", "dep_delay", "distance", "year_planes", "seats")]
## Call boxplot function
plot_boxplot(arr_delay_df, by = "arr_delay")Entre todos los cambios sutiles en correlación con los retrasos en las llegadas, se puede detectar inmediatamente que los aviones con más de 300 asientos tienden a tener retrasos mucho más largos (16 ~ 21 horas). Ahora podemos profundizar más para verificar o generar más hipótesis.
Para mirar las relaciones entre variables podemos visualizar scatterplots o diagramas de dispersión.
arr_delay_df2 <- final_data[, c("arr_delay", "dep_time", "dep_delay", "arr_time", "air_time", "distance", "year_planes", "seats")]
plot_scatterplot(arr_delay_df2, by = "arr_delay", sampled_rows = 1000L)El último paso del flujo es comunicar los resultados. Este puede tener diferentes caminos, dependiendo del público.
Shiny
app.Documentos de R Markdown (como
este documento) son formas de realizar informes, donde se puede combinar
código, visualizaciones y descripciones (texto). Se puede realizar
documentos, presentaciones, htmls, entre otros. Este tiene la ventaja
que podemos escribir ecuaciones como en \(\LaTeX\), como por ejemplo:
\[ \int_{0}^{\infty} e^{-s \cdot t} f(t) d t=\lim _{h \rightarrow \infty} \int_{0}^{h} e^{-s, t} f(t) d t \]
Si desea publicar sus hallazgos para la comunidad científica, puede escribir un artículo.
También puede publicarlo en línea para que cualquiera pueda acceder a él.
La idea con esta sesión es que aprendes, recuerdes o mejores tus habilidades de programación en R. La programación es una habilidad transversal para todo científico de datos.
El código también lo podemos ver como una herramienta de comunicación con otras personas, adicionalmente que es la forma de decirle a tu computadora que debe de hacer. Pensar en código como un medio de comunicación nos puede ayudar a trabajar mejor en proyectos colaborativos.
Incluso si no trabajas con personas, puede que tu mismo necesites tu código hacia el futuro y es mejor construir tu código de tal forma que, si otra persona, o tu en el futuro lo requieras volver a ver, sea fácil y rápido de entender.
Si es la primera vez que usas R te recomiendo que estudies un poco más de lo adicional a las clases, el libro Advanced R by Hadley Wickham, te puede ayudar y dar mayores ideas de cómo programar en R.
Los pipes son una herramienta para escribir código
secuencial de múltiples operaciones. El pipe %>%
proviene del paquete magrittr, pero el paquete de
tidyverse cargan el %>% de forma
automática, por lo que no es necesario que tengamos el paquete
magrittr especificado explícitamente.
El objetivo de los pipes es ayudarte de escribir código de tal forma que sea más fácil de leer y de entender.
Un ejemplo es transformar un dataframe por medio de filtros,
agrupaciones, etc. Esta forma de transformar los datos lo hacemos con la
ayuda del paquete dplyr que ya viene dentro de
tidyverse. Para ver todas las funciones que tiene este
paquete para transformación de datos aquí te dejo un
link que te puede ayudar.
# dataframe original
head(mpg)
# data frame transformado con pipe
mpg %>% filter(manufacturer == 'audi') %>%
group_by(year) %>% summarise(cty_mean = mean(cty),
hwy_mean = mean(hwy)) Las funciones nos permiten automatizar tareas comunes de manera más potente y general que copiar y pegar. Escribir una función tiene tres ventajas principales:
Puede dar a una función un nombre que te de idea de qué hace el código.
Cuando se requiera cambiar, sólo se cambia una vez, en lugar de que si tenemos el mismo código repetido, tenemos que cambiarlo las veces que lo tengamos repetido.
Se elimina la posibilidad de cometer errores.
Deberías considerar escribir una función siempre que hayas copiado y pegado un cloque de código más de dos veces. Veamos un ejemplo:
df <- tibble::tibble(
a = rnorm(10),
b = rnorm(10),
c = rnorm(10),
d = rnorm(10)
)
df$a <- (df$a - min(df$a, na.rm = TRUE)) /
(max(df$a, na.rm = TRUE) - min(df$a, na.rm = TRUE))
df$b <- (df$b - min(df$b, na.rm = TRUE)) /
(max(df$b, na.rm = TRUE) - min(df$a, na.rm = TRUE))
df$c <- (df$c - min(df$c, na.rm = TRUE)) /
(max(df$c, na.rm = TRUE) - min(df$c, na.rm = TRUE))
df$d <- (df$d - min(df$d, na.rm = TRUE)) /
(max(df$d, na.rm = TRUE) - min(df$d, na.rm = TRUE))Este código lo que hace es que reescala cada columna del dataframe
df para que tenga un valor entre 0 y 1. Pero, hay un error
en el código cuando se copió y pegó en df$b, en el momento
de copiar y pegar hay una a en una parte del código en
lugar de una b. ¿Lo viste?.
Para escribir una función hay que analizar primero el código. ¿Cuántas entradas tiene,? veamos la parte que se repite:
(df$a - min(df$a, na.rm = TRUE)) /
(max(df$a, na.rm = TRUE) - min(df$a, na.rm = TRUE)) [1] 0.6534246 1.0000000 0.6283353 0.6692940 0.8508011 0.7059234 0.8038226 0.2597706 0.6712101 0.0000000
Este código, la parte que vamos a cambiar es df$a, es
decir sólo tiene una variable de entrada si lo vemos como una función.
Lo que estamos haciendo en el código con el máximo y el mínimo en
realidad es mirar su rango, podemos utilizar función
range(), para su cálculo de tal forma que, la primera
entrada es el mínimo y la segunda el máximo, así, la función que
crearemos será:
# Función
rescale01 <- function(x) {
rng <- range(x, na.rm = TRUE)
(x - rng[1]) / (rng[2] - rng[1])
}
#Evaluación de la función
rescale01(c(0, 5, 10))[1] 0.0 0.5 1.0
Hay tres pasos claves para crear una función:
Elegir correctamente el nombre de la función.
Enumerar las entradas o argumentos de la función.
Que tu código dentro de la función dependa de las variables de entrada.
Con esta función, se resuelve el problema original donde teníamos el error nos quedaría de la siguiente forma:
df$a <- rescale01(df$a)
df$b <- rescale01(df$b)
df$c <- rescale01(df$c)
df$d <- rescale01(df$d)Una de las herramientas para ayudarnos a evitar duplicar código son las iteraciones, aunque debemos de tener cuidado con ellas y no darles un mal uso.
Volviendo al ejemplo anterior
df <- tibble(
a = rnorm(10),
b = rnorm(10),
c = rnorm(10),
d = rnorm(10)
)queremos calcular la media por columna, podríamos copiar y pegar realizarlo:
median(df$a)[1] -0.8089347
median(df$b)[1] -0.5162528
median(df$c)[1] -0.02820393
median(df$d)[1] -0.4217826
Una alternativa para no copiar y pegar es hacer un bucle:
output <- vector("double", ncol(df)) # 1. output
for (i in seq_along(df)) { # 2. sequence
output[[i]] <- median(df[[i]]) # 3. body
}
output[1] -0.80893474 -0.51625280 -0.02820393 -0.42178257
Par los bucles o loops tenemos tres componente:
La salida
output <- vector("double", length(x))
na forma general de crear un vector vacío de una longitud
determinada es la función vector()
La secuencia: i en seq_along(df). Esto determina lo
que se va a recorrer en el bucle: cada ejecución del bucle
for asignará a i un valor diferente de
seq_along(df).
Exploración y limpieza de datos para los siguientes dataframe:
Coffee ratings
conjunto de datos que mide la calificación del café según sus
características. Variable respuesta: cupper_points.
German Credit Ristk
que contiene variables de crédito para realizar un score de probabilidad
(si la persona paga o no paga) según sus características. Variable
respuesta: Risk.
Para cada conjunto de datos van a realizar un Rmarkdown,
donde se presente la exploración y limpieza de los datos. Si usted
considera que se debe de adicionar una variable o modificar el dataset
con agrupaciones o filtros por favor especificarlo en el reporte.
Antes de comenzar con el reporte hacerse una pregunta sobre los datos y responder a ella por medio de una o más visualizaciones. Al final del reporte colocar sus principales hallazgos y conclusiones.
NOTA: No se trata de hacer visualizaciones por hacerlas, cada una debe de ir acompañada de un análisis respecto a la variable respuesta para cada modelo.